
package com.csc440.team2.communication;

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;


import android.content.Context;
import android.content.Intent;
import android.telephony.SmsManager;
import android.util.Log;


import com.csc440.team2.SmilConstants;
import com.csc440.team2.database.entities.FolderType;
import com.csc440.team2.database.entities.Message;


public class ClientHandler implements Runnable
{

    private List<byte[]> queue;
    private List<Byte> input;
    private String key;
    private String message;
    private String reciever;
    private String sender;
    private int port;

    MessageAction action;

    Context context;


    public Context getContext()
    {
        return context;
    }


    public void setContext(Context context)
    {
        this.context = context;
    }


    public void setSender(String sender)
    {
        this.sender = sender;
    }


    public String setSender()
    {
        return this.sender;
    }


    public String getKey()
    {
        return key;
    }


    public void setKey(String key)
    {
        this.key = key;
    }


    public void setReciever(String reciever)
    {
        this.reciever = reciever;
    }


    public String getReciever()
    {
        return this.reciever;
    }


    public void setAction(MessageAction action)
    {
        this.action = action;
    }


    public MessageAction getAction()
    {
        return this.action;
    }


    public int getPort()
    {
        return port;
    }


    public void setPort(int port)
    {
        this.port = port;
    }


    public void setData(byte[] data)
    {
        queue = new ArrayList<byte[]>();
        queue.add(data);
    }


    public void setData(String data)
    {
        setData(stringToByteArray(data));
    }


    public void appendData(byte[] data)
    {
        if (queue == null)
        {
            setData(data);
        }
        else
        {
            queue.add(data);
        }
    }


    public void appendData(String data)
    {
        appendData(stringToByteArray(data));
    }


    private byte[] stringToByteArray(String string)
    {
        byte[] result = new byte[string.length()];
        int index;

        for (index = 0; index < string.length(); ++index)
        {
            result[index] = (byte) string.charAt(index);
        }

        return result;
    }


    private void sendEscapedByte(Socket connection, byte value)
    {
        try
        {
            connection.getOutputStream().write(escapeByte(value));
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }


    private void sendByte(Socket connection, byte value)
    {
        try
        {
            connection.getOutputStream().write(value);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }


    private void sendBytes(Socket connection, byte[] data)
    {
        int index;
        int length = data.length;

        for (index = 0; index < length; ++index)
        {
            sendEscapedByte(connection, data[index]);
        }
        sendByte(connection, (byte) 0);
    }


    private byte[] escapeByte(byte value)
    {
        byte[] result;
        if (value == 0)
        {
            result = new byte[] {
                    1, 2
            };
        }
        else if (value == 1)
        {
            result = new byte[] {
                    1, 1
            };
        }
        else
        {
            result = new byte[] {
                value
            };
        }
        return result;
    }


    protected void readInput(Socket connection)
    {
        byte unescapedInput = 0;
        int input = 0;
        boolean escapeFlag = false;
        boolean newLine = true;

        try
        {
            do
            {
                input = connection.getInputStream().read();
                if (input != -1)
                {
                    if (input == 0 && newLine)
                    {
                        break;
                    }
                    else
                    {
                        if (input == 0)
                        {
                            newline();
                            newLine = true;
                        }
                        else
                        {
                            newLine = false;
                            if (escapeFlag)
                            {
                                unescapedInput = unescapeByte((byte) input);
                                escapeFlag = false;
                            }
                            else
                            {
                                if (input == 1)
                                {
                                    escapeFlag = true;
                                }
                                else
                                {
                                    unescapedInput = (byte) input;
                                }
                            }
                            if (!escapeFlag)
                            {
                                processInput(unescapedInput);
                            }
                        }
                    }
                }
            }
            while (input != -1);

        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }


    private byte unescapeByte(byte value)
    {
        switch (value)
        {
            case 1:
                return 1;
            case 2:
                return 0;
        }
        return value;
    }


    protected void newline()
    {
        if (action == MessageAction.SEND)
        {
            key = byteListToString(input);
            Log.d("ClientHandler", key);
            SmsManager manager = SmsManager.getDefault();
            manager.sendTextMessage(this.reciever, null, key, null, null);
        }
        else if (action == MessageAction.RECIEVE)
        {
            message = byteListToString(input);
            Log.d("ClientHandler", message);
        }
    }


    protected void processInput(byte value)
    {
        input.add(value);
    }


    protected void printDebugMessage(String message)
    {
        System.out.println(message);
    }


    private String byteListToString(List<Byte> bytes)
    {
        // byte currentByte;
        String result = "";

        for (byte currentByte : bytes)
        {
            result += (char) currentByte;
        }

        return result;
    }


    private void send()
    {
        int index;
        try
        {
            Socket connection = new Socket("8.8.198.203", port);
            sendBytes(connection, stringToByteArray("send"));
            sendByte(connection, (byte) 0);
            for (index = 0; index < queue.size(); ++index)
            {
                sendBytes(connection, queue.get(index));
            }
            sendByte(connection, (byte) 0);
            input = new ArrayList<Byte>();
            readInput(connection);
        }
        catch (UnknownHostException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }


    private void recieve()
    {
        Intent smilRecievedIntent;
        try
        {
            Socket connection = new Socket("8.8.198.203", port);
            sendBytes(connection, stringToByteArray("recieve"));
            sendByte(connection, (byte) 0);
            sendBytes(connection, stringToByteArray(key));
            sendByte(connection, (byte) 0);
            input = new ArrayList<Byte>();
            readInput(connection);

            Message savedMessage = saveMessage(sender, message);

            smilRecievedIntent = new Intent("com.csc440.team2.intents.SMILRecieved");
            smilRecievedIntent.putExtra(SmilConstants.MESSAGE, savedMessage);
            context.sendBroadcast(smilRecievedIntent);
        }
        catch (UnknownHostException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }


    private Message saveMessage(String sender, String messageText)
    {
        Message message = new Message(messageText, FolderType.INBOX, false, sender);
        message.save(context);
        return message;
    }


    @Override
    public void run()
    {
        if (action == MessageAction.SEND)
        {
            send();
        }
        else if (action == MessageAction.RECIEVE)
        {
            recieve();
        }
    }
}
